/*
 * axi_uart.c
 *	485/422 串口测试
 *      Author: limou
 */

#include "axi_uart.h"
#include <sys/mman.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>


#define UART_NUM 6
#define AXI_uart_Len 4096

#define XUartLite_ReadReg(BaseAddress, RegOffset) \
		Xil_In32((BaseAddress) + (RegOffset))

#define XUartLite_WriteReg(BaseAddress, RegOffset, Data) \
		Xil_Out32((BaseAddress) + (RegOffset), (unsigned int)(Data))

void printHex1(unsigned char * rbuf, int len, int uint, char *name) {
    int cnt = 0;
    int index = 0;
    printf("\n%s", name);
    for(cnt = 0; cnt < len; cnt++) {
        if(cnt%uint == 0) {
            index++;
            printf("\n ==> %02d: ", index);
        }
        printf("%02x ", rbuf[cnt]);
    }
    printf("\n");
}

#define AXGPIO_PHYADDR   0x41200000   // 0 TB, 1 KZ, 2 ZJ 

#define UART485_PHYADDR2 0x42c20000   // TB
#define UART485_PHYADDR3 0x42c30000   // KZ
#define UART485_PHYADDR4 0x42c40000   // ZJ

#define GPIO_ADDR1     0 //TB
#define GPIO_ADDR2     1 //KZ
#define GPIO_ADDR3     2 //ZJ

#define CUR_GPIO_ADDR GPIO_ADDR3
#define CUR_UART_ADDR UART485_PHYADDR4

unsigned int uart_addr[UART_NUM] = { CUR_UART_ADDR, 0,0,0,0,0};
void * MAP_uart_addr[UART_NUM] = { 0,0,0,0,0,0 };

unsigned int * addr_axigpio;

void axi_gpio_init() {
    int fd = open("/dev/mem", O_RDWR | O_NOCTTY);
    if(fd < 0) {
        printf("error open /dev/mem; fd: %d \n", fd);
        return;
    }
    addr_axigpio = (unsigned int *)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, AXGPIO_PHYADDR);
    printf("addr_axigpio %p \n", addr_axigpio);
}

void setAxiGpioVal(int val, int addr) {
    addr_axigpio[0] = (val << addr);
    // printf("set axi gpio, addr -> val: %d -> %d\n", addr, val);
}

//write
static unsigned int Xil_Out32(unsigned long long Addr, unsigned int Value)
{
	volatile unsigned int *LocalAddr = (volatile unsigned int *)Addr;
	*LocalAddr = Value;
	return 0;
}

//read
static unsigned int Xil_In32(unsigned long long Addr)
{
	return *(volatile unsigned int *)Addr;
}


unsigned int Axi_Uart_Send(unsigned int num,unsigned char *SendBuf,unsigned int NumByte)
{

	unsigned int SendCount = 0;
	unsigned int StatusRegister;
	unsigned int IntrEnableStatus;
	unsigned int send_timeout_cnt = 0;

	//get status
	StatusRegister = XUartLite_ReadReg(MAP_uart_addr[num],XUL_STATUS_REG_OFFSET);

	XUartLite_WriteReg(MAP_uart_addr[num],XUL_CONTROL_REG_OFFSET, 0);

	IntrEnableStatus = StatusRegister;

	//send buffer
	while ((SendCount < NumByte))
	{
		if((StatusRegister & XUL_SR_TX_FIFO_FULL) == 0)
		{
			XUartLite_WriteReg(MAP_uart_addr[num],XUL_TX_FIFO_OFFSET,SendBuf[SendCount]);

			SendCount++;
		}
		else
		{
			send_timeout_cnt++;
			if(send_timeout_cnt>20000)
			{
				//				SendCount = NumByte;
				printf("SendCount=%d\n",SendCount);
				break;
			}
		}

		StatusRegister = XUartLite_ReadReg(MAP_uart_addr[num],XUL_STATUS_REG_OFFSET);
	}

	IntrEnableStatus &= XUL_CR_ENABLE_INTR;

	XUartLite_WriteReg(MAP_uart_addr[num], XUL_CONTROL_REG_OFFSET,IntrEnableStatus);

	return SendCount;
}

unsigned int Axi_Uart_Recv(unsigned int num,unsigned char* RecvBuf,unsigned int NumByte)
{
	unsigned int RecvCount = 0;
	unsigned int StatusRegister;
	unsigned int StatusRegisterVal;
	unsigned int recv_timeout_cnt = 0;

	StatusRegisterVal = XUartLite_ReadReg(MAP_uart_addr[num],XUL_STATUS_REG_OFFSET);

	XUartLite_WriteReg(MAP_uart_addr[num],XUL_CONTROL_REG_OFFSET, 0);

	while (RecvCount < NumByte)
	{

		StatusRegister = XUartLite_ReadReg(MAP_uart_addr[num],XUL_STATUS_REG_OFFSET);


		if (StatusRegister & XUL_SR_RX_FIFO_VALID_DATA)
		{
			RecvBuf[RecvCount++]=XUartLite_ReadReg(MAP_uart_addr[num],XUL_RX_FIFO_OFFSET);

		}
		else
		{
#if 1
			recv_timeout_cnt++;
			if(recv_timeout_cnt>20000)
			{
				//				SendCount = NumByte;

				if(RecvCount != 0) {
					printf("RecvCount=%d\n",RecvCount);
					printHex1(RecvBuf, RecvCount, RecvCount, "RecvBuf");
				}

				break;
			}
#endif		
			//#if 1
			//
			//			break;
			//
			//#endif	
		}
	}
	StatusRegisterVal &= XUL_CR_ENABLE_INTR;
	XUartLite_WriteReg(MAP_uart_addr[num],XUL_CONTROL_REG_OFFSET, StatusRegisterVal);

	return RecvCount;
}



void uart_init() 
{
	int fd = 0;
    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
    {
    	printf("open error !\r\n");
        return 0;
    }
  /* Map one page */ //���ں˿ռ�ӳ�䵽�û��ռ�
    MAP_uart_addr[0] = mmap(0, AXI_uart_Len, PROT_READ | PROT_WRITE, MAP_SHARED, fd,uart_addr[0]);
    if(MAP_uart_addr[0] == (void *) -1)
    {
    	printf("mmap error !\r\n");
        close(fd);
        return 0;
    }

	printf("uart mmap phy_addr -> virAddr: %p %p\n", uart_addr[0], MAP_uart_addr[0]);

}

void uart_test()
{

	unsigned int err = 0;
	unsigned int len = 10;
	unsigned char sendbuff1[len];
	unsigned char sendbuff2[len];
	unsigned char recvbuff[len];
	unsigned int i =0;

	uart_init();

	for(i=0;i<len;i++)
	{
		sendbuff1[i] = i;
	}

	for(i=0;i<len;i++)
	{
		sendbuff2[i] = ~i;
	}
	// while(1)
	// {

	// 	Axi_Uart_Send(0,sendbuff1,len);
	// 	Axi_Uart_Recv(0,recvbuff,len);
	// 	for(i=0;i<len;i++)
	// 	{
	// 		if(recvbuff[i] != sendbuff1[i])
	// 		{
	// 			printf("check failed !\n");
	// 		}
	// 	}


	// }
	axi_gpio_init();
	setAxiGpioVal(1, CUR_GPIO_ADDR);
	Axi_Uart_Send(0,sendbuff1,len);
	printHex1(sendbuff1, len, len, "SendBuf");

	
	usleep(10*1000);
	setAxiGpioVal(0, CUR_GPIO_ADDR);
	while(1) {
		Axi_Uart_Recv(0,recvbuff,len);
	}
	
}


int main(int argc, char const *argv[])
{
	uart_test();
	return 0;
}
